using System;
using UnityEngine;
using System.Collections;

public class PlanEvadeHerder : Plan
{
	FleeBehaviour fleeBehaviour = new FleeBehaviour();
	private AgentBehaviourScript agent;
	private Maze maze;
	private Vector3 currentDestination;
	private Plan currentPlan = null;	
	private Plan nextPlan = null;
	
	private float runDistance; 
	private const float herderObsticleSize = 16.5f;
	
	private const float recalculateRouteFrequency = 0.3f;
	private float nextPathUpdate;
	bool positionReached = false;
	GameController gameController;
		
	public PlanEvadeHerder (AgentBehaviourScript agent, Maze maze, Vector3 currentDestination)
	{
		this.currentDestination = currentDestination;
		this.agent = agent;
		this.maze = maze;
		
		nextPathUpdate = Time.timeSinceLevelLoad + recalculateRouteFrequency;
		
		runDistance = maze.getCellSize() * (3.0f);
		
		gameController = (GameController)GameObject. FindWithTag("GameController").GetComponent("GameController");
	}
	
	public override bool execute()
	{
		if (agent.getNearestHerder() == null)
			return false; 
			
		if (maze.getMazeCoord(agent.getPosition()) == maze.getMazeCoord(currentDestination))
		{
			positionReached = true;
		}
			
		if (agent.getDistanceToNearestHerder() < runDistance || positionReached) // if too close just run
		{
			currentPlan = null;
			nextPlan = null;
			agent.setDestination(fleeBehaviour.getSteering(agent)); // herder too close, just run
			return true; 
		}
		
		//agents should not try to avoid all herders when avioding - not just the closest
		ArrayList obstacles = new ArrayList();
		ArrayList herders = gameController.getHerders();
		foreach (HerderBehaviourScript herder in herders)
		{
			Vector3 herderPos = herder.getPosition(); 
			obstacles.AddRange(maze.getCircleArea(maze.getMazeCoord(herderPos),5.0f));
		}
		
		if (nextPlan == null)
		{
			if (Time.timeSinceLevelLoad	> nextPathUpdate)
			{
				nextPlan = new PlanPathFindToPosition(agent, maze, currentDestination, obstacles);	
				nextPathUpdate = Time.timeSinceLevelLoad + recalculateRouteFrequency;
			}
		}else
		{
			nextPlan.execute();
			if (nextPlan.getPathPlanner() != null && nextPlan.getPathPlanner().is_goal_found())
			{
				currentPlan = nextPlan;
				nextPlan = null;
			}
		}
		
		if (currentPlan == null)
		{
			currentPlan = new PlanPathFindToPosition(agent, maze, currentDestination, obstacles);
		}else
		{
			if (!currentPlan.execute())
			{
				// Don't know what to do, evade to a random position
				while(true)
				{
					float x = UnityEngine.Random.value * (maze.getWidth());	
					float y = UnityEngine.Random.value * (maze.getHeight());	
					
					currentDestination = maze.getMazePosition(new MazeLocation((int)x,(int)y)); 
					if(maze.getMazeSquare(maze.getMazeCoord(currentDestination)).isSolid() == false)
					{
						break;
					} 
				}
					
				return false; // finished path	
			}
			if (currentPlan.getPathPlanner() != null && !currentPlan.getPathPlanner().is_goal_found())
			{
				agent.setDestination(fleeBehaviour.getSteering(agent)); // run while thinking
			}
			return true;  // continuing on path
		}
		return true;
	}
	
	public override pathplanner getPathPlanner ()
	{
		if (currentPlan	!= null) {
			return currentPlan.getPathPlanner();
		} else {
			return null;
		}
	}

	public override string ToString ()
	{
		string returnString = string.Format ("Evade Herder( ");
		
		if (agent.getNearestHerder() != null)
		{
			if (agent.getDistanceToNearestHerder() < runDistance)
			{
				returnString += "Too close to herder; running!";
			}else
			{
				returnString += "Rerouting...";	
			}
		}
			
		if (currentPlan != null)
			returnString += currentPlan.ToString();
		returnString += " )";
		return returnString;
	}	
	
	
}

